//Rust中的并发安全，是通过Sync和Send这两个trait来体现的。
// Send表示的含义是，变量可以跨越线程的边界进行传递；Sync表示的含义是，变量可以多线程同时访问。

use std::sync::Arc;
use std::sync::Mutex;
use std::thread;

fn test1() {
    let mut a = vec![1, 2, 3];

    let handler = std::thread::spawn(move || {
        a.push(4);
    });

    handler.join().unwrap();
}

fn test2() {
    let mut a = vec![1, 2, 3];

    thread::scope(|s| {
        s.spawn(|| {
            println!("hello from the first scoped thread");
            a.push(4);
        });
    });

    a.push(5);
}

fn test3() {
    let a1 = Arc::new(vec![1, 2, 3]);
    let a2 = a1.clone();

    let handler = thread::spawn(move || {
        println!("a1 {:?}", a1);
    });

    println!("a2 {:?}", a2);

    handler.join().unwrap();
}

fn test4() {
    // 创建一个可互斥访问的集合
    let a1 = Arc::new(Mutex::new(vec![1, 2, 3]));
    // 克隆a1 创建两个新的引用。因为直接在子线程内使用a1会导致主线程的a1被move
    let a2 = a1.clone();
    let a3 = a1.clone();

    println!("a1  堆内存地址 {:p}", Arc::<_>::as_ptr(&a1));
    println!("a2  堆内存地址 {:p}", Arc::<_>::as_ptr(&a2));
    println!("a3  堆内存地址 {:p}", Arc::<_>::as_ptr(&a3));
    // 使用clone共享内存引用
    // a1  堆内存地址 0x25fd0349d10
    // a2  堆内存地址 0x25fd0349d10
    // a3  堆内存地址 0x25fd0349d10

    // 创建两个线程 来修改a1和a2的内部数据
    let t1 = thread::spawn(move || {
        let mut lock_guard = a1.lock().unwrap();
        lock_guard.push(4);
    });

    let t2 = thread::spawn(move || {
        let mut lock_guard = a2.lock().unwrap();
        lock_guard.push(4);
    });

    // 主线程等待t1 t2完成后再打印a3的内容
    t1.join().unwrap(); // unwrap方法获得线程的返回值
    t2.join().unwrap();
    println!("a3 {:?}", a3.lock().unwrap());
}

#[test]
pub fn main() {
    test1();
    test2();
    test3();
    test4();
}